package com.sojson.project.sys.dept.service.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sojson.base.impl.BaseUser;
import com.sojson.config.mybatis.annotation.DataScope;
import com.sojson.constant.ConstantField;
import com.sojson.constant.DataScopeType;
import com.sojson.enums.EEnvironmentUserType;
import com.sojson.project.sys.dept.dao.DeptDao;
import com.sojson.project.sys.dept.entity.dto.DeptDto;
import com.sojson.project.sys.dept.entity.dto.DeptPageDto;
import com.sojson.project.sys.dept.entity.po.Dept;
import com.sojson.project.sys.dept.entity.vo.DeptVo;
import com.sojson.project.sys.dept.service.DeptService;
import com.sojson.project.sys.menu.entity.bo.TreeSelect;
import com.sojson.project.sys.role.dao.RoleDao;
import com.sojson.project.sys.role.entity.po.UserDept;
import com.sojson.project.sys.role.service.UserDeptService;
import com.sojson.util.ExpUtil;
import com.sojson.util.StringUtil;
import com.sojson.util.param.ParamUtil;
import com.sojson.util.token.TokenUtil;

/**
 * 部门信息表Service实现类
 * 
 * @author liu
 * @date 2022-11-18
 */
@Service
public class DeptServiceImpl extends ServiceImpl<DeptDao, Dept> implements DeptService {

    @Lazy
    @Autowired
    private DeptService deptService;
    @Autowired
    private UserDeptService userDeptService;
    @Resource
    private DeptDao deptDao;
    @Resource
    private RoleDao roleDao;

    /**
     * 单条插入
     * 
     * @param dto
     * @return
     * @throws IOException 
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(Dept dto) throws IOException {
        if (countByName(dto) > 0) {
            ExpUtil.throwEx("部门名称已存在!");
        }

        // 添加部门
        deptDao.insert(dto);

        // 给当前用户添加此部门
        if (!ParamUtil.isAdminSuper()) {
            UserDept userDept = new UserDept();
            userDept.setUserId(TokenUtil.getUserId());
            userDept.setDeptId(dto.getId());
            userDeptService.save(userDept);
        }
        return true;
    }

    /**
     * 通过id更新
     * 
     * @param dto
     * @return
     * @throws IOException 
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(Dept dto) throws IOException {
        Dept selectById = deptDao.selectById(dto.getId());
        if (selectById == null) {
            return true;
        }
        String parentIdNew = dto.getParentId();
        String parentIdOld = selectById.getParentId();
        // 新权限不是空并且跟旧权限不一致就校验旧权限
        if (StringUtil.isNotBlank(parentIdNew) && !parentIdNew.equals(parentIdOld)) {
            ParamUtil.verifyDept(parentIdOld);
        }
        if (countByName(dto) > 0) {
            ExpUtil.throwEx("部门名称已存在!");
        }

        // 修改当前部门
        deptDao.updateById(dto);
        return true;
    }

    /**
     * 通过对象查找
     * 
     * @param dto
     * @return
     */
    @Override
    @DataScope(deptAlias = "d", deptField = ConstantField.ID)
    public List<DeptVo> list(DeptDto dto) {
        List<DeptVo> list = deptDao.list(dto);
        return list;
    }

    /**
     * 通过对象分页查找
     * 
     * @param dto
     * @return
     */
    @Override
    @DataScope(deptAlias = "d", deptField = ConstantField.ID)
    public List<DeptVo> page(DeptPageDto dto) {
        List<DeptVo> page = deptDao.page(dto);
        return page;
    }

    /**
     * 通过对象删除
     * 
     * @param dto
     * @return
     */
    @Override
    public boolean removeByDto(DeptDto dto) {
        deptDao.removeByDto(dto);
        return true;
    }

    /**
     * 清空数据
     * 
     * @return
     */
    @Override
    public boolean clear() {
        deptDao.clear();
        return true;
    }

    /**
     * 通过id查找
     * 
     * @param id
     * @return
     * @throws IOException 
     */
    @Override
    public DeptVo findById(String id) throws IOException {
        DeptVo findById = deptDao.findById(id);
        return findById;
    }

    /**
     * 通过id删除
     * 
     * @param id
     * @return
     * @throws IOException 
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(String id) throws IOException {
        if (deptService.hasChildById(id)) {
            ExpUtil.throwEx("存在下级部门,不允许删除!");
        }
        if (deptService.checkDeptExistUser(id)) {
            ExpUtil.throwEx("部门存在用户,不允许删除!");
        }

        deptDao.deleteById(id);
        return true;
    }

    /**
     * 通过id修改状态
     * 
     * @param dto
     * @return
     * @throws IOException 
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(Dept dto) throws IOException {
        deptDao.updateById(dto);
        return true;
    }

    /**
     * 通过部门名称统计数量
     * 
     * @param dto
     * @return
     */
    @Override
    public int countByName(Dept dto) {
        Dept dept = new Dept();
        dept.setId(dto.getId());
        dept.setName(dto.getName());
        return deptDao.countByName(dept);
    }

    /**
     * 判断是否存在子部门
     * 
     * @param id
     * @return
     */
    @Override
    public boolean hasChildById(String id) {
        return deptDao.hasChildById(id) > 0;
    }

    /**
     * 判断部门是否存在用户
     * 
     * @param id
     * @return
     */
    @Override
    public boolean checkDeptExistUser(String id) {
        LambdaQueryWrapper<Dept> queryUser = Wrappers.lambdaQuery(Dept.class);
        queryUser.eq(Dept::getId, id);
        int count = deptService.count(queryUser);
        if (count > 0) {
            return true;
        }

        LambdaQueryWrapper<UserDept> queryUserDept = Wrappers.lambdaQuery(UserDept.class);
        queryUserDept.eq(UserDept::getDeptId, id);
        count = userDeptService.count(queryUserDept);
        if (count > 0) {
            return true;
        }

        return false;
    }

    /**
     * 构建前端所需要树结构
     *
     * @param dto 部门列表
     * @return 树结构列表
     */
    @Override
    public List<DeptVo> buildDeptTree(List<DeptVo> dto) {
        // 构件好的集合
        List<DeptVo> returnList = new ArrayList<>();
        // 所有部门的ID
        List<String> tempList = new ArrayList<>();
        for (DeptVo dept : dto) {
            tempList.add(dept.getId());
        }
        for (Iterator<DeptVo> iterator = dto.iterator(); iterator.hasNext();) {
            DeptVo dept = iterator.next();
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(dto, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = dto;
        }
        return returnList;
    }

    /**
     * 递归列表
     * 
     * @param list
     * @param t
     */
    private void recursionFn(List<DeptVo> list, DeptVo t) {
        // 得到子节点列表
        List<DeptVo> childList = getChildList(list, t);
        t.setChildren(childList);
        for (DeptVo tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     * 
     * @param list
     * @param t
     * @return
     */
    private List<DeptVo> getChildList(List<DeptVo> list, DeptVo t) {
        List<DeptVo> tlist = new ArrayList<>();
        Iterator<DeptVo> it = list.iterator();
        while (it.hasNext()) {
            DeptVo n = it.next();
            if (n.getParentId() != null && n.getParentId().equals(t.getId())) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     * 
     * @param list
     * @param t
     * @return
     */
    private boolean hasChild(List<DeptVo> list, DeptVo t) {
        return getChildList(list, t).size() > 0;
    }

    /**
     * 构建前端所需要下拉树结构
     *
     * @param dto   部门列表
     * @return 下拉树结构列表
     */
    @Override
    public List<TreeSelect> buildDeptTreeSelect(List<DeptVo> dto) {
        List<DeptVo> deptTrees = buildDeptTree(dto);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    /**
     * 根据用户ID查询部门树信息
     *
     * @param userId    用户ID
     * @return 选中部门列表
     */
    @Override
    public List<String> selectDeptListByUserId(DeptDto dto) {
        String userEnv = dto.getUserEnv();
        String tableName = null;
        EEnvironmentUserType[] values = EEnvironmentUserType.values();
        for (EEnvironmentUserType env : values) {
            if(env.getCode().equals(userEnv)) {
                tableName = env.getTableName();
                break;
            }
        }
        if(tableName == null) {
            ExpUtil.throwEx("环境不存在");
        }

        boolean deptCheckStrictly = deptDao.getUserDeptCheckStrictlyById(tableName, dto.getUserId());
        return deptDao.selectDeptListByUserId(dto.getUserId(), deptCheckStrictly);
    }

    /**
     * 根据角色ID查询部门树信息
     *
     * @param roleId    角色ID
     * @return 选中部门列表
     */
    @Override
    public List<String> selectDeptListByRoleId(String roleId) {
        // Role role = roleDao.selectById(roleId);
        // return deptDao.selectDeptListByRoleId(roleId, role.getDeptCheckStrictly());
        return null;
    }

    /**
     * 查询部门ID列表
     * 
     * @param dto
     * @return
     * @throws IOException 
     */
    @Override
    public Set<String> listIds(BaseUser dto) throws IOException {
        Integer dataScope = dto.getDataScope();

        Set<String> depts = new HashSet<>();
        DeptDto deptDto = new DeptDto();
        if (DataScopeType.DATA_SCOPE_ALL == dataScope) {
        } else if (DataScopeType.DATA_SCOPE_CUSTOM == dataScope) {
            deptDto.setUserId(dto.getId());
            depts = deptDao.listIds(deptDto);
        } else if (DataScopeType.DATA_SCOPE_DEPT == dataScope) {
            deptDto.setId(dto.getDeptId());
            depts = new HashSet<>();
            depts.add(deptDao.getUserDeptId(dto.getId()));
        } else if (DataScopeType.DATA_SCOPE_DEPT_AND_CHILD == dataScope) {
            deptDto.setId(dto.getDeptId());
            depts = deptDao.listIds(deptDto);
        } else if (DataScopeType.DATA_SCOPE_SELF == dataScope) {
        }
        return depts;
    }

}